﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.IO;
using System.Collections;


// XMLNode与XmlElement的关系
// XmlElement 类型的结点属于XMLNode中的一种的结点，XML中所有结点类型都是从XMLNode这个抽象类中具体实现出来的，
// 这一点可以从XmlElement，xmlComment等结点直接或者间接继承于XMLNode中看出来
// 结点有很多种包括：注释结点，元素结点，文本结点等
// 可以使用XmlDocument实例CreadNode方式创建任意类型的结点，也可使用XmlDocument实例Creat结点类型的特定方法创建指定结点
namespace XML学习
{
    static class XMLFile
    {
        private  static XmlDocument _xmldoc;
        
        /// <summary>
        /// 打开一个已存在的xml文件，如果文件不存在就创建一个新的
        /// </summary>
        /// <param name="xmlFilePath">要打开的xml文件的路径</param>
        /// <param name="rootNodeName">如果是新建的xml文件，给定此文件的根节点</param>
        public static void Open(string xmlFilePath,string xmlRootNodeName)
        {
            XmlDocument xmldoc = new XmlDocument();
           
            _xmlElementDic.Clear();

            if (File.Exists(xmlFilePath))
            {
                xmldoc.Load(xmlFilePath);

                _xmlElementDic[xmldoc.DocumentElement.LocalName] = xmldoc.DocumentElement;

                RefreshNodeList(xmldoc.DocumentElement, xmldoc.DocumentElement.LocalName);                
              
                Console.WriteLine(xmlFilePath + "打开成功");               
            }
            else
            {
                // 1 引用命名空间
                // 2 创建一个XML文档对象

                // 3 创建第一行用于描述性息的结点
                XmlDeclaration docFirstLine = xmldoc.CreateXmlDeclaration("1.0", "utf-8", null);
                xmldoc.AppendChild(docFirstLine);
                // 4 创建一个根节点,且根节点必须是一个元素结点
                XmlNode rootNode = xmldoc.CreateNode(XmlNodeType.Element, xmlRootNodeName, "");
                //XmlElement rootNode = xmldoc.CreateElement(xmlRootNodeName);
               
                xmldoc.AppendChild(rootNode);

                _xmlElementDic.Add(rootNode.LocalName, rootNode);

                // 以上就是创建一个新的xml文件必须的要素

                Console.WriteLine("xmldoc结点是一个" + xmldoc.NodeType.ToString() + "结点");                               
                Console.WriteLine("使用xmldoc.CreateXmlDeclaration创建的结点是一个" + docFirstLine.NodeType.ToString() + "结点");               
                Console.WriteLine("使用doc.CreatDocumentElement创建的结点是一个" + rootNode.NodeType.ToString() + "结点");
                Console.WriteLine("使用doc.CreatDocumentElement创建的结点是一个" + xmldoc.DocumentElement.NodeType.ToString() + "结点");

                Console.WriteLine(xmlFilePath + "创建成功");
            }

            _xmldoc = xmldoc;
            
        }

        public static void Close(string xmlFilePath)
        {                       
            _xmldoc.Save(xmlFilePath);
        }

        public static Dictionary<string, XmlNode> _xmlElementDic = new Dictionary<string, XmlNode>();

        /// <summary>
        /// 在有根节点的情况下追加新结点
        /// </summary>
        /// <param name="childLabel">要追加的结点的标签</param>
        /// <param name="parentLabel">追加标签的所在上级标签，顺序必须是由高级到低级的顺序</param>
        /// <returns>返回本次追加的结点对象</returns>
        public static XmlNode AppendNewNode(string childLabel, params string[] parentLabel)
        {
            if (_xmlElementDic.Count == 0)
            {
                return null;
            }
            string parentNames = "";

            XmlNode node = _xmldoc.CreateNode(XmlNodeType.Element, childLabel,"");
            for (int i = 0; i < parentLabel.Length; i++)
            {
                parentNames += parentLabel[i];
            }
            _xmlElementDic[parentNames].AppendChild(node);
            parentNames += node.LocalName;
            _xmlElementDic[parentNames] = node;

            return node;
        }     


        /// <summary>
        /// 对于已经存在的xml文件，对其结点信息递归刷新
        /// </summary>
        /// <param name="parentNode">待递归的结点</param>
        /// <param name="fullPath">带递归结点路径</param>
        private static void RefreshNodeList(XmlNode parentNode, string fullPath)
        {
            string childNodePath = "";

            for (int i = 0; i < parentNode.ChildNodes.Count; i++)
            {
                if (parentNode.NodeType == XmlNodeType.Element)
                {
                    //continue;
                    //将所有节点,无论是element结点还是text类型的结点，都将他们的路径信息存入字典
                }

                XmlNode childNode = parentNode.ChildNodes.Item(i);
                childNodePath = fullPath + childNode.LocalName;
                _xmlElementDic[childNodePath] = childNode;
                RefreshNodeList(childNode, childNodePath);
            }
        }

        /// <summary>
        /// 读取路径匹配xpath的所有结点
        /// </summary>
        /// <param name="xpath">结点所在全路径</param>
        /// <returns>xpath路径下节点列表</returns>
        public static XmlNodeList ReadNodeInfor(string xpath)
        {
            return _xmldoc.SelectNodes(xpath);
        }

        /// <summary>
        /// 删除第一个匹配xpath路径结点的所有子节点
        /// </summary>
        /// <param name="xpath"></param>
        public static void DeleteNode(string xpath)
        {
            XmlNode xmlnode;
            xmlnode =  _xmldoc.SelectSingleNode(xpath);
            xmlnode.RemoveAll();
        }

    }
}
